home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / gawk-3.000 / gawk-3 / gawk-3.0.0 / awk.y < prev    next >
Encoding:
Text File  |  1995-12-31  |  51.4 KB  |  2,321 lines

  1. /*
  2.  * awk.y --- yacc/bison parser
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989, 1991-1995 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Programming Language.
  10.  * 
  11.  * GAWK is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  * 
  16.  * GAWK is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  * 
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
  24.  */
  25.  
  26. %{
  27. #ifdef DEBUG
  28. #define YYDEBUG 12
  29. #endif
  30.  
  31. #include "awk.h"
  32.  
  33. #define CAN_FREE    TRUE
  34. #define DONT_FREE    FALSE
  35.  
  36. #if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__
  37. static void yyerror(const char *m, ...) ;
  38. #else
  39. static void yyerror(); /* va_alist */
  40. #endif
  41. static char *get_src_buf P((void));
  42. static int yylex P((void));
  43. static NODE *node_common P((NODETYPE op));
  44. static NODE *snode P((NODE *subn, NODETYPE op, int sindex));
  45. static NODE *mkrangenode P((NODE *cpair));
  46. static NODE *make_for_loop P((NODE *init, NODE *cond, NODE *incr));
  47. static NODE *append_right P((NODE *list, NODE *new));
  48. static void func_install P((NODE *params, NODE *def));
  49. static void pop_var P((NODE *np, int freeit));
  50. static void pop_params P((NODE *params));
  51. static NODE *make_param P((char *name));
  52. static NODE *mk_rexp P((NODE *exp));
  53. static int dup_parms P((NODE *func));
  54. static void param_sanity P((NODE *arglist));
  55. static int isnoeffect P((NODETYPE));
  56.  
  57. enum defref { FUNC_DEFINE, FUNC_USE };
  58. static void func_use P((char *name, enum defref how));
  59. static void check_funcs P((void));
  60.  
  61. static int want_assign;        /* lexical scanning kludge */
  62. static int want_regexp;        /* lexical scanning kludge */
  63. static int can_return;        /* lexical scanning kludge */
  64. static int io_allowed = TRUE;    /* lexical scanning kludge */
  65. static char *lexptr;        /* pointer to next char during parsing */
  66. static char *lexend;
  67. static char *lexptr_begin;    /* keep track of where we were for error msgs */
  68. static char *lexeme;        /* beginning of lexeme for debugging */
  69. static char *thisline = NULL;
  70. #define YYDEBUG_LEXER_TEXT (lexeme)
  71. static int param_counter;
  72. static char *tokstart = NULL;
  73. static char *tok = NULL;
  74. static char *tokend;
  75.  
  76. #define HASHSIZE    1021    /* this constant only used here */
  77. NODE *variables[HASHSIZE];
  78.  
  79. extern char *source;
  80. extern int sourceline;
  81. extern struct src *srcfiles;
  82. extern int numfiles;
  83. extern int errcount;
  84. extern NODE *begin_block;
  85. extern NODE *end_block;
  86. %}
  87.  
  88. %union {
  89.     long lval;
  90.     AWKNUM fval;
  91.     NODE *nodeval;
  92.     NODETYPE nodetypeval;
  93.     char *sval;
  94.     NODE *(*ptrval)();
  95. }
  96.  
  97. %type <nodeval> function_prologue function_body
  98. %type <nodeval> rexp exp start program rule simp_exp
  99. %type <nodeval> non_post_simp_exp
  100. %type <nodeval> pattern 
  101. %type <nodeval>    action variable param_list
  102. %type <nodeval>    rexpression_list opt_rexpression_list
  103. %type <nodeval>    expression_list opt_expression_list
  104. %type <nodeval>    statements statement if_statement opt_param_list 
  105. %type <nodeval> opt_exp opt_variable regexp 
  106. %type <nodeval> input_redir output_redir
  107. %type <nodetypeval> print
  108. %type <sval> func_name
  109. %type <lval> lex_builtin
  110.  
  111. %token <sval> FUNC_CALL NAME REGEXP
  112. %token <lval> ERROR
  113. %token <nodeval> YNUMBER YSTRING
  114. %token <nodetypeval> RELOP APPEND_OP
  115. %token <nodetypeval> ASSIGNOP MATCHOP NEWLINE CONCAT_OP
  116. %token <nodetypeval> LEX_BEGIN LEX_END LEX_IF LEX_ELSE LEX_RETURN LEX_DELETE
  117. %token <nodetypeval> LEX_WHILE LEX_DO LEX_FOR LEX_BREAK LEX_CONTINUE
  118. %token <nodetypeval> LEX_PRINT LEX_PRINTF LEX_NEXT LEX_EXIT LEX_FUNCTION
  119. %token <nodetypeval> LEX_GETLINE LEX_NEXTFILE
  120. %token <nodetypeval> LEX_IN
  121. %token <lval> LEX_AND LEX_OR INCREMENT DECREMENT
  122. %token <lval> LEX_BUILTIN LEX_LENGTH
  123.  
  124. /* these are just yylval numbers */
  125.  
  126. /* Lowest to highest */
  127. %right ASSIGNOP
  128. %right '?' ':'
  129. %left LEX_OR
  130. %left LEX_AND
  131. %left LEX_GETLINE
  132. %nonassoc LEX_IN
  133. %left FUNC_CALL LEX_BUILTIN LEX_LENGTH
  134. %nonassoc ','
  135. %nonassoc MATCHOP
  136. %nonassoc RELOP '<' '>' '|' APPEND_OP
  137. %left CONCAT_OP
  138. %left YSTRING YNUMBER
  139. %left '+' '-'
  140. %left '*' '/' '%'
  141. %right '!' UNARY
  142. %right '^'
  143. %left INCREMENT DECREMENT
  144. %left '$'
  145. %left '(' ')'
  146. %%
  147.  
  148. start
  149.     : opt_nls program opt_nls
  150.         {
  151.             expression_value = $2;
  152.             check_funcs();
  153.         }
  154.     ;
  155.  
  156. program
  157.     : rule
  158.         { 
  159.             if ($1 != NULL)
  160.                 $$ = $1;
  161.             else
  162.                 $$ = NULL;
  163.             yyerrok;
  164.         }
  165.     | program rule
  166.         /* add the rule to the tail of list */
  167.         {
  168.             if ($2 == NULL)
  169.                 $$ = $1;
  170.             else if ($1 == NULL)
  171.                 $$ = $2;
  172.             else {
  173.                 if ($1->type != Node_rule_list)
  174.                     $1 = node($1, Node_rule_list,
  175.                         (NODE*) NULL);
  176.                 $$ = append_right($1,
  177.                    node($2, Node_rule_list, (NODE *) NULL));
  178.             }
  179.             yyerrok;
  180.         }
  181.     | error    { $$ = NULL; }
  182.     | program error { $$ = NULL; }
  183.     | /* empty */ { $$ = NULL; }
  184.     ;
  185.  
  186. rule
  187.     : LEX_BEGIN { io_allowed = FALSE; }
  188.       action
  189.       {
  190.         if (begin_block != NULL) {
  191.             if (begin_block->type != Node_rule_list)
  192.                 begin_block = node(begin_block, Node_rule_list,
  193.                     (NODE *) NULL);
  194.             (void) append_right(begin_block, node(
  195.                 node((NODE *) NULL, Node_rule_node, $3),
  196.                 Node_rule_list, (NODE *) NULL) );
  197.         } else
  198.             begin_block = node((NODE *) NULL, Node_rule_node, $3);
  199.         $$ = NULL;
  200.         io_allowed = TRUE;
  201.         yyerrok;
  202.       }
  203.     | LEX_END { io_allowed = FALSE; }
  204.       action
  205.       {
  206.         if (end_block != NULL) {
  207.             if (end_block->type != Node_rule_list)
  208.                 end_block = node(end_block, Node_rule_list,
  209.                     (NODE *) NULL);
  210.             (void) append_right (end_block, node(
  211.                 node((NODE *) NULL, Node_rule_node, $3),
  212.                 Node_rule_list, (NODE *) NULL));
  213.         } else
  214.             end_block = node((NODE *) NULL, Node_rule_node, $3);
  215.         $$ = NULL;
  216.         io_allowed = TRUE;
  217.         yyerrok;
  218.       }
  219.     | LEX_BEGIN statement_term
  220.       {
  221.         warning("BEGIN blocks must have an action part");
  222.         errcount++;
  223.         yyerrok;
  224.       }
  225.     | LEX_END statement_term
  226.       {
  227.         warning("END blocks must have an action part");
  228.         errcount++;
  229.         yyerrok;
  230.       }
  231.     | pattern action
  232.         { $$ = node($1, Node_rule_node, $2); yyerrok; }
  233.     | action
  234.         { $$ = node((NODE *) NULL, Node_rule_node, $1); yyerrok; }
  235.     | pattern statement_term
  236.         {
  237.           $$ = node($1,
  238.                  Node_rule_node,
  239.                  node(node(node(make_number(0.0),
  240.                         Node_field_spec,
  241.                         (NODE *) NULL),
  242.                     Node_expression_list,
  243.                     (NODE *) NULL),
  244.                   Node_K_print,
  245.                   (NODE *) NULL));
  246.           yyerrok;
  247.         }
  248.     | function_prologue function_body
  249.         {
  250.             func_install($1, $2);
  251.             $$ = NULL;
  252.             yyerrok;
  253.         }
  254.     ;
  255.  
  256. func_name
  257.     : NAME
  258.         { $$ = $1; }
  259.     | FUNC_CALL
  260.         { $$ = $1; }
  261.     | lex_builtin
  262.       {
  263.         yyerror("%s() is a built-in function, it cannot be redefined",
  264.             tokstart);
  265.         errcount++;
  266.         /* yyerrok; */
  267.       }
  268.     ;
  269.  
  270. lex_builtin
  271.     : LEX_BUILTIN
  272.     | LEX_LENGTH
  273.     ;
  274.         
  275. function_prologue
  276.     : LEX_FUNCTION 
  277.         {
  278.             param_counter = 0;
  279.         }
  280.       func_name '(' opt_param_list r_paren opt_nls
  281.         {
  282.             $$ = append_right(make_param($3), $5);
  283.             can_return = TRUE;
  284.             /* check for duplicate parameter names */
  285.             if (dup_parms($$))
  286.                 errcount++;
  287.         }
  288.     ;
  289.  
  290. function_body
  291.     : l_brace statements r_brace opt_semi
  292.       {
  293.         $$ = $2;
  294.         can_return = FALSE;
  295.       }
  296.     | l_brace r_brace opt_semi opt_nls
  297.       {
  298.         $$ = node((NODE *) NULL, Node_K_return, (NODE *) NULL);
  299.         can_return = FALSE;
  300.       }
  301.     ;
  302.  
  303.  
  304. pattern
  305.     : exp
  306.         { $$ = $1; }
  307.     | exp ',' exp
  308.         { $$ = mkrangenode(node($1, Node_cond_pair, $3)); }
  309.     ;
  310.  
  311. regexp
  312.     /*
  313.      * In this rule, want_regexp tells yylex that the next thing
  314.      * is a regexp so it should read up to the closing slash.
  315.      */
  316.     : '/'
  317.         { ++want_regexp; }
  318.       REGEXP '/'
  319.         {
  320.           NODE *n;
  321.           size_t len;
  322.  
  323.           getnode(n);
  324.           n->type = Node_regex;
  325.           len = strlen($3);
  326.           n->re_exp = make_string($3, len);
  327.           n->re_reg = make_regexp($3, len, FALSE, TRUE);
  328.           n->re_text = NULL;
  329.           n->re_flags = CONST;
  330.           n->re_cnt = 1;
  331.           $$ = n;
  332.         }
  333.     ;
  334.  
  335. action
  336.     : l_brace statements r_brace opt_semi opt_nls
  337.         { $$ = $2; }
  338.     | l_brace r_brace opt_semi opt_nls
  339.         { $$ = NULL; }
  340.     ;
  341.  
  342. statements
  343.     : statement
  344.         {
  345.             $$ = $1;
  346.             if (do_lint && isnoeffect($$->type))
  347.                 warning("statement may have no effect");
  348.         }
  349.     | statements statement
  350.         {
  351.             if ($1 == NULL || $1->type != Node_statement_list)
  352.                 $1 = node($1, Node_statement_list, (NODE *) NULL);
  353.                 $$ = append_right($1,
  354.                 node($2, Node_statement_list, (NODE *)   NULL));
  355.                 yyerrok;
  356.         }
  357.     | error
  358.         { $$ = NULL; }
  359.     | statements error
  360.         { $$ = NULL; }
  361.     ;
  362.  
  363. statement_term
  364.     : nls
  365.     | semi opt_nls
  366.     ;
  367.  
  368. statement
  369.     : semi opt_nls
  370.         { $$ = NULL; }
  371.     | l_brace r_brace
  372.         { $$ = NULL; }
  373.     | l_brace statements r_brace
  374.         { $$ = $2; }
  375.     | if_statement
  376.         { $$ = $1; }
  377.     | LEX_WHILE '(' exp r_paren opt_nls statement
  378.         { $$ = node($3, Node_K_while, $6); }
  379.     | LEX_DO opt_nls statement LEX_WHILE '(' exp r_paren opt_nls
  380.         { $$ = node($6, Node_K_do, $3); }
  381.     | LEX_FOR '(' NAME LEX_IN NAME r_paren opt_nls statement
  382.       {
  383.         $$ = node($8, Node_K_arrayfor,
  384.             make_for_loop(variable($3, CAN_FREE, Node_var),
  385.             (NODE *) NULL, variable($5, CAN_FREE, Node_var_array)));
  386.       }
  387.     | LEX_FOR '(' opt_exp semi exp semi opt_exp r_paren opt_nls statement
  388.       {
  389.         $$ = node($10, Node_K_for, (NODE *) make_for_loop($3, $5, $7));
  390.       }
  391.     | LEX_FOR '(' opt_exp semi semi opt_exp r_paren opt_nls statement
  392.       {
  393.         $$ = node($9, Node_K_for,
  394.             (NODE *) make_for_loop($3, (NODE *) NULL, $6));
  395.       }
  396.     | LEX_BREAK statement_term
  397.        /* for break, maybe we'll have to remember where to break to */
  398.         { $$ = node((NODE *) NULL, Node_K_break, (NODE *) NULL); }
  399.     | LEX_CONTINUE statement_term
  400.        /* similarly */
  401.         { $$ = node((NODE *) NULL, Node_K_continue, (NODE *) NULL); }
  402.     | print '(' expression_list r_paren output_redir statement_term
  403.         { $$ = node($3, $1, $5); }
  404.     | print opt_rexpression_list output_redir statement_term
  405.         {
  406.             if ($1 == Node_K_print && $2 == NULL) {
  407.                 static int warned = FALSE;
  408.  
  409.                 $2 = node(node(make_number(0.0),
  410.                            Node_field_spec,
  411.                            (NODE *) NULL),
  412.                       Node_expression_list,
  413.                       (NODE *) NULL);
  414.  
  415.                 if (do_lint && ! io_allowed && ! warned) {
  416.                     warned = TRUE;
  417.                     warning(
  418.     "plain `print' in BEGIN or END rule should probably be `print \"\"'");
  419.                 }
  420.             }
  421.  
  422.             $$ = node($2, $1, $3);
  423.         }
  424.     | LEX_NEXT opt_exp statement_term
  425.         { NODETYPE type;
  426.  
  427.           if ($2) {
  428.             if ($2 == lookup("file")) {
  429.                 static int warned = FALSE;
  430.  
  431.                 if (! warned) {
  432.                     warned = TRUE;
  433.                     warning("`next file' is obsolete; use `nextfile'");
  434.                 }
  435.                 if (do_lint)
  436.                     warning("`next file' is a gawk extension");
  437.                 if (do_traditional) {
  438.                     /*
  439.                      * can't use yyerror, since may have overshot
  440.                      * the source line
  441.                      */
  442.                     errcount++;
  443.                     error("`next file' is a gawk extension");
  444.                 }
  445.                 if (! io_allowed) {
  446.                     /* same thing */
  447.                     errcount++;
  448.                     error("`next file' used in BEGIN or END action");
  449.                 }
  450.                 type = Node_K_nextfile;
  451.             } else {
  452.                 errcount++;
  453.                 error("illegal expression after `next'");
  454.                 type = Node_K_next;    /* sanity */
  455.             }
  456.           } else {
  457.             if (! io_allowed)
  458.                 yyerror("`next' used in BEGIN or END action");
  459.             type = Node_K_next;
  460.           }
  461.           $$ = node((NODE *) NULL, type, (NODE *) NULL);
  462.         }
  463.     | LEX_NEXTFILE statement_term
  464.         {
  465.           if (do_lint)
  466.             warning("`nextfile' is a gawk extension");
  467.           if (do_traditional) {
  468.             /*
  469.              * can't use yyerror, since may have overshot
  470.              * the source line
  471.              */
  472.             errcount++;
  473.             error("`nextfile' is a gawk extension");
  474.           }
  475.           if (! io_allowed) {
  476.             /* same thing */
  477.             errcount++;
  478.             error("`nextfile' used in BEGIN or END action");
  479.           }
  480.           $$ = node((NODE *) NULL, Node_K_nextfile, (NODE *) NULL);
  481.         }
  482.     | LEX_EXIT opt_exp statement_term
  483.         { $$ = node($2, Node_K_exit, (NODE *) NULL); }
  484.     | LEX_RETURN
  485.         {
  486.           if (! can_return)
  487.             yyerror("`return' used outside function context");
  488.         }
  489.       opt_exp statement_term
  490.         { $$ = node($3, Node_K_return, (NODE *) NULL); }
  491.     | LEX_DELETE NAME '[' expression_list ']' statement_term
  492.         { $$ = node(variable($2, CAN_FREE, Node_var_array), Node_K_delete, $4); }
  493.     | LEX_DELETE NAME  statement_term
  494.         {
  495.           if (do_lint)
  496.             warning("`delete array' is a gawk extension");
  497.           if (do_traditional) {
  498.             /*
  499.              * can't use yyerror, since may have overshot
  500.              * the source line
  501.              */
  502.             errcount++;
  503.             error("`delete array' is a gawk extension");
  504.           }
  505.           $$ = node(variable($2, CAN_FREE, Node_var_array), Node_K_delete, (NODE *) NULL);
  506.         }
  507.     | exp statement_term
  508.         { $$ = $1; }
  509.     ;
  510.  
  511. print
  512.     : LEX_PRINT
  513.         { $$ = $1; }
  514.     | LEX_PRINTF
  515.         { $$ = $1; }
  516.     ;
  517.  
  518. if_statement
  519.     : LEX_IF '(' exp r_paren opt_nls statement
  520.       {
  521.         $$ = node($3, Node_K_if, 
  522.             node($6, Node_if_branches, (NODE *) NULL));
  523.       }
  524.     | LEX_IF '(' exp r_paren opt_nls statement
  525.          LEX_ELSE opt_nls statement
  526.         { $$ = node($3, Node_K_if,
  527.                 node($6, Node_if_branches, $9)); }
  528.     ;
  529.  
  530. nls
  531.     : NEWLINE
  532.         { want_assign = FALSE; }
  533.     | nls NEWLINE
  534.     ;
  535.  
  536. opt_nls
  537.     : /* empty */
  538.     | nls
  539.     ;
  540.  
  541. input_redir
  542.     : /* empty */
  543.         { $$ = NULL; }
  544.     | '<' simp_exp
  545.         { $$ = node($2, Node_redirect_input, (NODE *) NULL); }
  546.     ;
  547.  
  548. output_redir
  549.     : /* empty */
  550.         { $$ = NULL; }
  551.     | '>' exp
  552.         { $$ = node($2, Node_redirect_output, (NODE *) NULL); }
  553.     | APPEND_OP exp
  554.         { $$ = node($2, Node_redirect_append, (NODE *) NULL); }
  555.     | '|' exp
  556.         { $$ = node($2, Node_redirect_pipe, (NODE *) NULL); }
  557.     ;
  558.  
  559. opt_param_list
  560.     : /* empty */
  561.         { $$ = NULL; }
  562.     | param_list
  563.         { $$ = $1; }
  564.     ;
  565.  
  566. param_list
  567.     : NAME
  568.         { $$ = make_param($1); }
  569.     | param_list comma NAME
  570.         { $$ = append_right($1, make_param($3)); yyerrok; }
  571.     | error
  572.         { $$ = NULL; }
  573.     | param_list error
  574.         { $$ = NULL; }
  575.     | param_list comma error
  576.         { $$ = NULL; }
  577.     ;
  578.  
  579. /* optional expression, as in for loop */
  580. opt_exp
  581.     : /* empty */
  582.         { $$ = NULL; }
  583.     | exp
  584.         { $$ = $1; }
  585.     ;
  586.  
  587. opt_rexpression_list
  588.     : /* empty */
  589.         { $$ = NULL; }
  590.     | rexpression_list
  591.         { $$ = $1; }
  592.     ;
  593.  
  594. rexpression_list
  595.     : rexp
  596.         { $$ = node($1, Node_expression_list, (NODE *) NULL); }
  597.     | rexpression_list comma rexp
  598.       {
  599.         $$ = append_right($1,
  600.             node($3, Node_expression_list, (NODE *) NULL));
  601.         yyerrok;
  602.       }
  603.     | error
  604.         { $$ = NULL; }
  605.     | rexpression_list error
  606.         { $$ = NULL; }
  607.     | rexpression_list error rexp
  608.         { $$ = NULL; }
  609.     | rexpression_list comma error
  610.         { $$ = NULL; }
  611.     ;
  612.  
  613. opt_expression_list
  614.     : /* empty */
  615.         { $$ = NULL; }
  616.     | expression_list
  617.         { $$ = $1; }
  618.     ;
  619.  
  620. expression_list
  621.     : exp
  622.         { $$ = node($1, Node_expression_list, (NODE *) NULL); }
  623.     | expression_list comma exp
  624.         {
  625.             $$ = append_right($1,
  626.                 node($3, Node_expression_list, (NODE *) NULL));
  627.             yyerrok;
  628.         }
  629.     | error
  630.         { $$ = NULL; }
  631.     | expression_list error
  632.         { $$ = NULL; }
  633.     | expression_list error exp
  634.         { $$ = NULL; }
  635.     | expression_list comma error
  636.         { $$ = NULL; }
  637.     ;
  638.  
  639. /* Expressions, not including the comma operator.  */
  640. exp    : variable ASSIGNOP 
  641.         { want_assign = FALSE; }
  642.       exp
  643.         {
  644.           if (do_lint && $4->type == Node_regex)
  645.             warning("Regular expression on left of assignment.");
  646.           $$ = node($1, $2, $4);
  647.         }
  648.     | '(' expression_list r_paren LEX_IN NAME
  649.         { $$ = node(variable($5, CAN_FREE, Node_var_array), Node_in_array, $2); }
  650.     | exp '|' LEX_GETLINE opt_variable
  651.         {
  652.           $$ = node($4, Node_K_getline,
  653.              node($1, Node_redirect_pipein, (NODE *) NULL));
  654.         }
  655.     | LEX_GETLINE opt_variable input_redir
  656.         {
  657.           if (do_lint && ! io_allowed && $3 == NULL)
  658.             warning("non-redirected getline undefined inside BEGIN or END action");
  659.           $$ = node($2, Node_K_getline, $3);
  660.         }
  661.     | exp LEX_AND exp
  662.         { $$ = node($1, Node_and, $3); }
  663.     | exp LEX_OR exp
  664.         { $$ = node($1, Node_or, $3); }
  665.     | exp MATCHOP exp
  666.         {
  667.           if ($1->type == Node_regex)
  668.             warning("Regular expression on left of MATCH operator.");
  669.           $$ = node($1, $2, mk_rexp($3));
  670.         }
  671.     | regexp
  672.         {
  673.           $$ = $1;
  674.           if (do_lint && tokstart[0] == '*') {
  675.             /* possible C comment */
  676.             int n = strlen(tokstart) - 1;
  677.             if (tokstart[n] == '*')
  678.                 warning("regexp looks like a C comment, but is not");
  679.           }
  680.         }
  681.     | '!' regexp %prec UNARY
  682.         {
  683.           $$ = node(node(make_number(0.0),
  684.                  Node_field_spec,
  685.                  (NODE *) NULL),
  686.                     Node_nomatch,
  687.                 $2);
  688.         }
  689.     | exp LEX_IN NAME
  690.         { $$ = node(variable($3, CAN_FREE, Node_var_array), Node_in_array, $1); }
  691.     | exp RELOP exp
  692.         {
  693.           if (do_lint && $3->type == Node_regex)
  694.             warning("Regular expression on left of comparison.");
  695.           $$ = node($1, $2, $3);
  696.         }
  697.     | exp '<' exp
  698.         { $$ = node($1, Node_less, $3); }
  699.     | exp '>' exp
  700.         { $$ = node($1, Node_greater, $3); }
  701.     | exp '?' exp ':' exp
  702.         { $$ = node($1, Node_cond_exp, node($3, Node_if_branches, $5));}
  703.     | simp_exp
  704.         { $$ = $1; }
  705.     | exp simp_exp %prec CONCAT_OP
  706.         { $$ = node($1, Node_concat, $2); }
  707.     ;
  708.  
  709. rexp    
  710.     : variable ASSIGNOP 
  711.         { want_assign = FALSE; }
  712.       rexp
  713.         { $$ = node($1, $2, $4); }
  714.     | rexp LEX_AND rexp
  715.         { $$ = node($1, Node_and, $3); }
  716.     | rexp LEX_OR rexp
  717.         { $$ = node($1, Node_or, $3); }
  718.     | LEX_GETLINE opt_variable input_redir
  719.         {
  720.           if (do_lint && ! io_allowed && $3 == NULL)
  721.             warning("non-redirected getline undefined inside BEGIN or END action");
  722.           $$ = node($2, Node_K_getline, $3);
  723.         }
  724.     | regexp
  725.         { $$ = $1; } 
  726.     | '!' regexp %prec UNARY
  727.         { $$ = node((NODE *) NULL, Node_nomatch, $2); }
  728.     | rexp MATCHOP rexp
  729.          { $$ = node($1, $2, mk_rexp($3)); }
  730.     | rexp LEX_IN NAME
  731.         { $$ = node(variable($3, CAN_FREE, Node_var_array), Node_in_array, $1); }
  732.     | rexp RELOP rexp
  733.         { $$ = node($1, $2, $3); }
  734.     | rexp '?' rexp ':' rexp
  735.         { $$ = node($1, Node_cond_exp, node($3, Node_if_branches, $5));}
  736.     | simp_exp
  737.         { $$ = $1; }
  738.     | rexp simp_exp %prec CONCAT_OP
  739.         { $$ = node($1, Node_concat, $2); }
  740.     ;
  741.  
  742. simp_exp
  743.     : non_post_simp_exp
  744.     /* Binary operators in order of decreasing precedence.  */
  745.     | simp_exp '^' simp_exp
  746.         { $$ = node($1, Node_exp, $3); }
  747.     | simp_exp '*' simp_exp
  748.         { $$ = node($1, Node_times, $3); }
  749.     | simp_exp '/' simp_exp
  750.         { $$ = node($1, Node_quotient, $3); }
  751.     | simp_exp '%' simp_exp
  752.         { $$ = node($1, Node_mod, $3); }
  753.     | simp_exp '+' simp_exp
  754.         { $$ = node($1, Node_plus, $3); }
  755.     | simp_exp '-' simp_exp
  756.         { $$ = node($1, Node_minus, $3); }
  757.     | variable INCREMENT
  758.         { $$ = node($1, Node_postincrement, (NODE *) NULL); }
  759.     | variable DECREMENT
  760.         { $$ = node($1, Node_postdecrement, (NODE *) NULL); }
  761.     ;
  762.  
  763. non_post_simp_exp
  764.     : '!' simp_exp %prec UNARY
  765.         { $$ = node($2, Node_not, (NODE *) NULL); }
  766.     | '(' exp r_paren
  767.         { $$ = $2; }
  768.     | LEX_BUILTIN
  769.       '(' opt_expression_list r_paren
  770.         { $$ = snode($3, Node_builtin, (int) $1); }
  771.     | LEX_LENGTH '(' opt_expression_list r_paren
  772.         { $$ = snode($3, Node_builtin, (int) $1); }
  773.     | LEX_LENGTH
  774.       {
  775.         if (do_lint)
  776.             warning("call of `length' without parentheses is not portable");
  777.         $$ = snode((NODE *) NULL, Node_builtin, (int) $1);
  778.         if (do_posix)
  779.             warning("call of `length' without parentheses is deprecated by POSIX");
  780.       }
  781.     | FUNC_CALL '(' opt_expression_list r_paren
  782.       {
  783.         $$ = node($3, Node_func_call, make_string($1, strlen($1)));
  784.         func_use($1, FUNC_USE);
  785.         param_sanity($3);
  786.         free($1);
  787.       }
  788.     | variable
  789.     | INCREMENT variable
  790.         { $$ = node($2, Node_preincrement, (NODE *) NULL); }
  791.     | DECREMENT variable
  792.         { $$ = node($2, Node_predecrement, (NODE *) NULL); }
  793.     | YNUMBER
  794.         { $$ = $1; }
  795.     | YSTRING
  796.         { $$ = $1; }
  797.  
  798.     | '-' simp_exp    %prec UNARY
  799.         {
  800.           if ($2->type == Node_val) {
  801.             $2->numbr = -(force_number($2));
  802.             $$ = $2;
  803.           } else
  804.             $$ = node($2, Node_unary_minus, (NODE *) NULL);
  805.         }
  806.     | '+' simp_exp    %prec UNARY
  807.         {
  808.           /*
  809.            * was: $$ = $2
  810.            * POSIX semantics: force a conversion to numeric type
  811.            */
  812.           $$ = node (make_number(0.0), Node_plus, $2);
  813.         }
  814.     ;
  815.  
  816. opt_variable
  817.     : /* empty */
  818.         { $$ = NULL; }
  819.     | variable
  820.         { $$ = $1; }
  821.     ;
  822.  
  823. variable
  824.     : NAME
  825.         { $$ = variable($1, CAN_FREE, Node_var); }
  826.     | NAME '[' expression_list ']'
  827.         {
  828.         if ($3->rnode == NULL) {
  829.             $$ = node(variable($1, CAN_FREE, Node_var_array), Node_subscript, $3->lnode);
  830.             freenode($3);
  831.         } else
  832.             $$ = node(variable($1, CAN_FREE, Node_var_array), Node_subscript, $3);
  833.         }
  834.     | '$' non_post_simp_exp
  835.         { $$ = node($2, Node_field_spec, (NODE *) NULL); }
  836.     ;
  837.  
  838. l_brace
  839.     : '{' opt_nls
  840.     ;
  841.  
  842. r_brace
  843.     : '}' opt_nls    { yyerrok; }
  844.     ;
  845.  
  846. r_paren
  847.     : ')' { yyerrok; }
  848.     ;
  849.  
  850. opt_semi
  851.     : /* empty */
  852.     | semi
  853.     ;
  854.  
  855. semi
  856.     : ';'    { yyerrok; want_assign = FALSE; }
  857.     ;
  858.  
  859. comma    : ',' opt_nls    { yyerrok; }
  860.     ;
  861.  
  862. %%
  863.  
  864. struct token {
  865.     const char *operator;        /* text to match */
  866.     NODETYPE value;        /* node type */
  867.     int class;        /* lexical class */
  868.     unsigned flags;        /* # of args. allowed and compatability */
  869. #    define    ARGS    0xFF    /* 0, 1, 2, 3 args allowed (any combination */
  870. #    define    A(n)    (1<<(n))
  871. #    define    VERSION    0xFF00    /* old awk is zero */
  872. #    define    NOT_OLD        0x0100    /* feature not in old awk */
  873. #    define    NOT_POSIX    0x0200    /* feature not in POSIX */
  874. #    define    GAWKX        0x0400    /* gawk extension */
  875. #    define    RESX        0x0800    /* Bell Labs Research extension */
  876.     NODE *(*ptr)();        /* function that implements this keyword */
  877. };
  878.  
  879. extern NODE
  880.     *do_exp(),    *do_getline(),    *do_index(),    *do_length(),
  881.     *do_sqrt(),    *do_log(),    *do_sprintf(),    *do_substr(),
  882.     *do_split(),    *do_system(),    *do_int(),    *do_close(),
  883.     *do_atan2(),    *do_sin(),    *do_cos(),    *do_rand(),
  884.     *do_srand(),    *do_match(),    *do_tolower(),    *do_toupper(),
  885.     *do_sub(),    *do_gsub(),    *do_strftime(),    *do_systime(),
  886.     *do_fflush();
  887.  
  888. /* Tokentab is sorted ascii ascending order, so it can be binary searched. */
  889.  
  890. static struct token tokentab[] = {
  891. {"BEGIN",    Node_illegal,     LEX_BEGIN,    0,        0},
  892. {"END",        Node_illegal,     LEX_END,    0,        0},
  893. {"atan2",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(2),    do_atan2},
  894. {"break",    Node_K_break,     LEX_BREAK,    0,        0},
  895. {"close",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(1),    do_close},
  896. {"continue",    Node_K_continue, LEX_CONTINUE,    0,        0},
  897. {"cos",        Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(1),    do_cos},
  898. {"delete",    Node_K_delete,     LEX_DELETE,    NOT_OLD,    0},
  899. {"do",        Node_K_do,     LEX_DO,    NOT_OLD,    0},
  900. {"else",    Node_illegal,     LEX_ELSE,    0,        0},
  901. {"exit",    Node_K_exit,     LEX_EXIT,    0,        0},
  902. {"exp",        Node_builtin,     LEX_BUILTIN,    A(1),        do_exp},
  903. {"fflush",    Node_builtin,     LEX_BUILTIN,    RESX|A(0)|A(1), do_fflush},
  904. {"for",        Node_K_for,     LEX_FOR,    0,        0},
  905. {"func",    Node_K_function, LEX_FUNCTION,    NOT_POSIX|NOT_OLD,    0},
  906. {"function",    Node_K_function, LEX_FUNCTION,    NOT_OLD,    0},
  907. {"gensub",    Node_builtin,     LEX_BUILTIN,    GAWKX|A(3)|A(4), do_gensub},
  908. {"getline",    Node_K_getline,     LEX_GETLINE,    NOT_OLD,    0},
  909. {"gsub",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(2)|A(3), do_gsub},
  910. {"if",        Node_K_if,     LEX_IF,    0,        0},
  911. {"in",        Node_illegal,     LEX_IN,    0,        0},
  912. {"index",    Node_builtin,     LEX_BUILTIN,    A(2),        do_index},
  913. {"int",        Node_builtin,     LEX_BUILTIN,    A(1),        do_int},
  914. {"length",    Node_builtin,     LEX_LENGTH,    A(0)|A(1),    do_length},
  915. {"log",        Node_builtin,     LEX_BUILTIN,    A(1),        do_log},
  916. {"match",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(2),    do_match},
  917. {"next",    Node_K_next,     LEX_NEXT,    0,        0},
  918. {"nextfile",    Node_K_nextfile, LEX_NEXTFILE,    GAWKX,        0},
  919. {"print",    Node_K_print,     LEX_PRINT,    0,        0},
  920. {"printf",    Node_K_printf,     LEX_PRINTF,    0,        0},
  921. {"rand",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(0),    do_rand},
  922. {"return",    Node_K_return,     LEX_RETURN,    NOT_OLD,    0},
  923. {"sin",        Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(1),    do_sin},
  924. {"split",    Node_builtin,     LEX_BUILTIN,    A(2)|A(3),    do_split},
  925. {"sprintf",    Node_builtin,     LEX_BUILTIN,    0,        do_sprintf},
  926. {"sqrt",    Node_builtin,     LEX_BUILTIN,    A(1),        do_sqrt},
  927. {"srand",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(0)|A(1), do_srand},
  928. {"strftime",    Node_builtin,     LEX_BUILTIN,    GAWKX|A(0)|A(1)|A(2), do_strftime},
  929. {"sub",        Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(2)|A(3), do_sub},
  930. {"substr",    Node_builtin,     LEX_BUILTIN,    A(2)|A(3),    do_substr},
  931. {"system",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(1),    do_system},
  932. {"systime",    Node_builtin,     LEX_BUILTIN,    GAWKX|A(0),    do_systime},
  933. {"tolower",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(1),    do_tolower},
  934. {"toupper",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(1),    do_toupper},
  935. {"while",    Node_K_while,     LEX_WHILE,    0,        0},
  936. };
  937.  
  938. /* yyerror --- print a syntax error message, show where */
  939.  
  940. #if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__
  941. static void
  942. yyerror(const char *m, ...)
  943. #else
  944. /* VARARGS0 */
  945. static void
  946. yyerror(va_alist)
  947. va_dcl
  948. #endif
  949. {
  950.     va_list args;
  951.     const char *mesg = NULL;
  952.     register char *bp, *cp;
  953.     char *scan;
  954.     char buf[120];
  955.     static char end_of_file_line[] = "(END OF FILE)";
  956.  
  957.     errcount++;
  958.     /* Find the current line in the input file */
  959.     if (lexptr && lexeme) {
  960.         if (thisline == NULL) {
  961.             cp = lexeme;
  962.             if (*cp == '\n') {
  963.                 cp--;
  964.                 mesg = "unexpected newline";
  965.             }
  966.             for (; cp != lexptr_begin && *cp != '\n'; --cp)
  967.                 continue;
  968.             if (*cp == '\n')
  969.                 cp++;
  970.             thisline = cp;
  971.         }
  972.         /* NL isn't guaranteed */
  973.         bp = lexeme;
  974.         while (bp < lexend && *bp && *bp != '\n')
  975.             bp++;
  976.     } else {
  977.         thisline = end_of_file_line;
  978.         bp = thisline + strlen(thisline);
  979.     }
  980.     msg("%.*s", (int) (bp - thisline), thisline);
  981.     bp = buf;
  982.     cp = buf + sizeof(buf) - 24;    /* 24 more than longest msg. input */
  983.     if (lexptr != NULL) {
  984.         scan = thisline;
  985.         while (bp < cp && scan < lexeme)
  986.             if (*scan++ == '\t')
  987.                 *bp++ = '\t';
  988.             else
  989.                 *bp++ = ' ';
  990.         *bp++ = '^';
  991.         *bp++ = ' ';
  992.     }
  993. #if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__
  994.     va_start(args, m);
  995.     if (mesg == NULL)
  996.         mesg = m;
  997. #else
  998.     va_start(args);
  999.     if (mesg == NULL)
  1000.         mesg = va_arg(args, char *);
  1001. #endif
  1002.     strcpy(bp, mesg);
  1003.     err("", buf, args);
  1004.     va_end(args);
  1005.     exit(2);
  1006. }
  1007.  
  1008. /* get_src_buf --- read the next buffer of source program */
  1009.  
  1010. static char *
  1011. get_src_buf()
  1012. {
  1013.     static int samefile = FALSE;
  1014.     static int nextfile = 0;
  1015.     static char *buf = NULL;
  1016.     static int fd;
  1017.     int n;
  1018.     register char *scan;
  1019.     static int len = 0;
  1020.     static int did_newline = FALSE;
  1021.     struct stat sbuf;
  1022.  
  1023. #    define    SLOP    128    /* enough space to hold most source lines */
  1024.  
  1025. again:
  1026.     if (nextfile > numfiles)
  1027.         return NULL;
  1028.  
  1029.     if (srcfiles[nextfile].stype == CMDLINE) {
  1030.         if (len == 0) {
  1031.             len = strlen(srcfiles[nextfile].val);
  1032.             if (len == 0) {
  1033.                 /*
  1034.                  * Yet Another Special case:
  1035.                  *    gawk '' /path/name
  1036.                  * Sigh.
  1037.                  */
  1038.                 static int warned = FALSE;
  1039.  
  1040.                 if (do_lint && ! warned) {
  1041.                     warned = TRUE;
  1042.                     warning("empty program text on command line");
  1043.                 }
  1044.                 ++nextfile;
  1045.                 goto again;
  1046.             }
  1047.             sourceline = 1;
  1048.             lexptr = lexptr_begin = srcfiles[nextfile].val;
  1049.             lexend = lexptr + len;
  1050.         } else if (! did_newline && *(lexptr-1) != '\n') {
  1051.             /*
  1052.              * The following goop is to ensure that the source
  1053.              * ends with a newline and that the entire current
  1054.              * line is available for error messages.
  1055.              */
  1056.             int offset;
  1057.  
  1058.             did_newline = TRUE;
  1059.             offset = lexptr - lexeme;
  1060.             for (scan = lexeme; scan > lexptr_begin; scan--)
  1061.                 if (*scan == '\n') {
  1062.                     scan++;
  1063.                     break;
  1064.                 }
  1065.             len = lexptr - scan;
  1066.             emalloc(buf, char *, len+1, "get_src_buf");
  1067.             memcpy(buf, scan, len);
  1068.             thisline = buf;
  1069.             lexptr = buf + len;
  1070.             *lexptr = '\n';
  1071.             lexeme = lexptr - offset;
  1072.             lexptr_begin = buf;
  1073.             lexend = lexptr + 1;
  1074.         } else {
  1075.             len = 0;
  1076.             lexeme = lexptr = lexptr_begin = NULL;
  1077.         }
  1078.         if (lexptr == NULL && ++nextfile <= numfiles)
  1079.             goto again;
  1080.         return lexptr;
  1081.     }
  1082.     if (! samefile) {
  1083.         source = srcfiles[nextfile].val;
  1084.         if (source == NULL) {
  1085.             if (buf != NULL) {
  1086.                 free(buf);
  1087.                 buf = NULL;
  1088.             }
  1089.             len = 0;
  1090.             return lexeme = lexptr = lexptr_begin = NULL;
  1091.         }
  1092.         fd = pathopen(source);
  1093.         if (fd <= INVALID_HANDLE) {
  1094.             char *in;
  1095.  
  1096.             /* suppress file name and line no. in error mesg */
  1097.             in = source;
  1098.             source = NULL;
  1099.             fatal("can't open source file \"%s\" for reading (%s)",
  1100.                 in, strerror(errno));
  1101.         }
  1102.         len = optimal_bufsize(fd, & sbuf);
  1103.         if (sbuf.st_size == 0) {
  1104.             static int warned = FALSE;
  1105.  
  1106.             if (do_lint && ! warned) {
  1107.                 warned = TRUE;
  1108.                 warning("source file `%s' is empty", source);
  1109.             }
  1110.             close(fd);
  1111.             ++nextfile;
  1112.             goto again;
  1113.         }
  1114.         if (buf != NULL)
  1115.             free(buf);
  1116.         emalloc(buf, char *, len + SLOP, "get_src_buf");
  1117.         lexptr_begin = buf + SLOP;
  1118.         samefile = TRUE;
  1119.         sourceline = 1;
  1120.     } else {
  1121.         /*
  1122.          * Here, we retain the current source line (up to length SLOP)
  1123.          * in the beginning of the buffer that was overallocated above
  1124.          */
  1125.         int offset;
  1126.         int linelen;
  1127.  
  1128.         offset = lexptr - lexeme;
  1129.         for (scan = lexeme; scan > lexptr_begin; scan--)
  1130.             if (*scan == '\n') {
  1131.                 scan++;
  1132.                 break;
  1133.             }
  1134.         linelen = lexptr - scan;
  1135.         if (linelen > SLOP)
  1136.             linelen = SLOP;
  1137.         thisline = buf + SLOP - linelen;
  1138.         memcpy(thisline, scan, linelen);
  1139.         lexeme = buf + SLOP - offset;
  1140.         lexptr_begin = thisline;
  1141.     }
  1142.     n = read(fd, buf + SLOP, len);
  1143.     if (n == -1)
  1144.         fatal("can't read sourcefile \"%s\" (%s)",
  1145.             source, strerror(errno));
  1146.     if (n == 0) {
  1147.         close(fd);
  1148.         samefile = FALSE;
  1149.         nextfile++;
  1150.         if (lexeme)
  1151.             *lexeme = '\0';
  1152.         len = 0;
  1153.         goto again;
  1154.     }
  1155.     lexptr = buf + SLOP;
  1156.     lexend = lexptr + n;
  1157.     return buf;
  1158. }
  1159.  
  1160. /* tokadd --- add a character to the token buffer */
  1161.  
  1162. #define    tokadd(x) (*tok++ = (x), tok == tokend ? tokexpand() : tok)
  1163.  
  1164. /* tokexpand --- grow the token buffer */
  1165.  
  1166. char *
  1167. tokexpand()
  1168. {
  1169.     static int toksize = 60;
  1170.     int tokoffset;
  1171.  
  1172.     tokoffset = tok - tokstart;
  1173.     toksize *= 2;
  1174.     if (tokstart != NULL)
  1175.         erealloc(tokstart, char *, toksize, "tokexpand");
  1176.     else
  1177.         emalloc(tokstart, char *, toksize, "tokexpand");
  1178.     tokend = tokstart + toksize;
  1179.     tok = tokstart + tokoffset;
  1180.     return tok;
  1181. }
  1182.  
  1183. /* nextc --- get the next input character */
  1184.  
  1185. #if DEBUG
  1186. int
  1187. nextc()
  1188. {
  1189.     int c;
  1190.  
  1191.     if (lexptr && lexptr < lexend)
  1192.         c = *lexptr++;
  1193.     else if (get_src_buf())
  1194.         c = *lexptr++;
  1195.     else
  1196.         c = EOF;
  1197.  
  1198.     return c;
  1199. }
  1200. #else
  1201. #define    nextc()    ((lexptr && lexptr < lexend) ? \
  1202.             *lexptr++ : \
  1203.             (get_src_buf() ? *lexptr++ : EOF) \
  1204.         )
  1205. #endif
  1206.  
  1207. /* pushback --- push a character back on the input */
  1208.  
  1209. #define pushback() (lexptr && lexptr > lexptr_begin ? lexptr-- : lexptr)
  1210.  
  1211. /* allow_newline --- allow newline after &&, ||, ? and : */
  1212.  
  1213. static void
  1214. allow_newline()
  1215. {
  1216.     int c;
  1217.  
  1218.     for (;;) {
  1219.         c = nextc();
  1220.         if (c == EOF)
  1221.             break;
  1222.         if (c == '#') {
  1223.             while ((c = nextc()) != '\n' && c != EOF)
  1224.                 continue;
  1225.             if (c == EOF)
  1226.                 break;
  1227.         }
  1228.         if (c == '\n')
  1229.             sourceline++;
  1230.         if (! isspace(c)) {
  1231.             pushback();
  1232.             break;
  1233.         }
  1234.     }
  1235. }
  1236.  
  1237. /* yylex --- Read the input and turn it into tokens. */
  1238.  
  1239. static int
  1240. yylex()
  1241. {
  1242.     register int c, c1;
  1243.     int seen_e = FALSE;        /* These are for numbers */
  1244.     int seen_point = FALSE;
  1245.     int esc_seen;        /* for literal strings */
  1246.     int low, mid, high;
  1247.     static int did_newline = FALSE;
  1248.     char *tokkey;
  1249.     static int lasttok = 0, eof_warned = FALSE;
  1250.  
  1251.     if (nextc() == EOF) {
  1252.         if (lasttok != NEWLINE) {
  1253.             lasttok = NEWLINE;
  1254.             if (do_lint && ! eof_warned) {
  1255.                 warning("source file does not end in newline");
  1256.                 eof_warned = TRUE;
  1257.             }
  1258.             return NEWLINE;    /* fake it */
  1259.         }
  1260.         return 0;
  1261.     }
  1262.     pushback();
  1263. #ifdef OS2
  1264.     /*
  1265.      * added for OS/2's extproc feature of cmd.exe
  1266.      * (like #! in BSD sh)
  1267.      */
  1268.     if (strncasecmp(lexptr, "extproc ", 8) == 0) {
  1269.         while (*lexptr && *lexptr != '\n')
  1270.             lexptr++;
  1271.     }
  1272. #endif
  1273.     lexeme = lexptr;
  1274.     thisline = NULL;
  1275.     if (want_regexp) {
  1276.         int in_brack = 0;    /* count brackets, [[:alnum:]] allowed */
  1277.         /*
  1278.          * Counting brackets is non-trivial. [[] is ok,
  1279.          * and so is [\]], with a point being that /[/]/ as a regexp
  1280.          * constant has to work.
  1281.          *
  1282.          * Do not count [ or ] if either one is preceded by a \.
  1283.          * A `[' should be counted if
  1284.          *  a) it is the first one so far (in_brack == 0)
  1285.          *  b) it is the `[' in `[:'
  1286.          * A ']' should be counted if not preceded by a \, since
  1287.          * it is either closing `:]' or just a plain list.
  1288.          * According to POSIX, []] is how you put a ] into a set.
  1289.          * Try to handle that too.
  1290.          *
  1291.          * The code for \ handles \[ and \].
  1292.          */
  1293.  
  1294.         want_regexp = FALSE;
  1295.         tok = tokstart;
  1296.         for (;;) {
  1297.             c = nextc();
  1298.             switch (c) {
  1299.             case '[':
  1300.                 /* one day check for `.' and `=' too */
  1301.                 if ((c1 = nextc()) == ':' || in_brack == 0)
  1302.                     in_brack++;
  1303.                 pushback();
  1304.                 break;
  1305.             case ']':
  1306.                 if (tokstart[0] == '['
  1307.                     && (tok == tokstart + 1
  1308.                     || (tok == tokstart + 2
  1309.                         && tokstart[1] == '^')))
  1310.                     /* do nothing */;
  1311.                 else
  1312.                     in_brack--;
  1313.                 break;
  1314.             case '\\':
  1315.                 if ((c = nextc()) == EOF) {
  1316.                     yyerror("unterminated regexp ends with \\ at end of file");
  1317.                     return lasttok = REGEXP; /* kludge */
  1318.                 } else if (c == '\n') {
  1319.                     sourceline++;
  1320.                     continue;
  1321.                 } else {
  1322.                     tokadd('\\');
  1323.                     tokadd(c);
  1324.                     continue;
  1325.                 }
  1326.                 break;
  1327.             case '/':    /* end of the regexp */
  1328.                 if (in_brack > 0)
  1329.                     break;
  1330.  
  1331.                 pushback();
  1332.                 tokadd('\0');
  1333.                 yylval.sval = tokstart;
  1334.                 return lasttok = REGEXP;
  1335.             case '\n':
  1336.                 pushback();
  1337.                 yyerror("unterminated regexp");
  1338.                 return lasttok = REGEXP;    /* kludge */
  1339.             case EOF:
  1340.                 yyerror("unterminated regexp at end of file");
  1341.                 return lasttok = REGEXP;    /* kludge */
  1342.             }
  1343.             tokadd(c);
  1344.         }
  1345.     }
  1346. retry:
  1347.     while ((c = nextc()) == ' ' || c == '\t')
  1348.         continue;
  1349.  
  1350.     lexeme = lexptr ? lexptr - 1 : lexptr;
  1351.     thisline = NULL;
  1352.     tok = tokstart;
  1353.     yylval.nodetypeval = Node_illegal;
  1354.  
  1355.     switch (c) {
  1356.     case EOF:
  1357.         if (lasttok != NEWLINE) {
  1358.             lasttok = NEWLINE;
  1359.             if (do_lint && ! eof_warned) {
  1360.                 warning("source file does not end in newline");
  1361.                 eof_warned = TRUE;
  1362.             }
  1363.             return NEWLINE;    /* fake it */
  1364.         }
  1365.         return 0;
  1366.  
  1367.     case '\n':
  1368.         sourceline++;
  1369.         return lasttok = NEWLINE;
  1370.  
  1371.     case '#':        /* it's a comment */
  1372.         while ((c = nextc()) != '\n') {
  1373.             if (c == EOF) {
  1374.                 if (lasttok != NEWLINE) {
  1375.                     lasttok = NEWLINE;
  1376.                     if (do_lint && ! eof_warned) {
  1377.                         warning(
  1378.                 "source file does not end in newline");
  1379.                         eof_warned = TRUE;
  1380.                     }
  1381.                     return NEWLINE;    /* fake it */
  1382.                 }
  1383.                 return 0;
  1384.             }
  1385.         }
  1386.         sourceline++;
  1387.         return lasttok = NEWLINE;
  1388.  
  1389.     case '\\':
  1390. #ifdef RELAXED_CONTINUATION
  1391.         /*
  1392.          * This code puports to allow comments and/or whitespace
  1393.          * after the `\' at the end of a line used for continuation.
  1394.          * Use it at your own risk. We think it's a bad idea, which
  1395.          * is why it's not on by default.
  1396.          */
  1397.         if (! do_traditional) {
  1398.             /* strip trailing white-space and/or comment */
  1399.             while ((c = nextc()) == ' ' || c == '\t')
  1400.                 continue;
  1401.             if (c == '#') {
  1402.                 if (do_lint)
  1403.                     warning(
  1404.         "use of `\\ #...' line continuation is not portable");
  1405.                 while ((c = nextc()) != '\n')
  1406.                     if (c == EOF)
  1407.                         break;
  1408.             }
  1409.             pushback();
  1410.         }
  1411. #endif /* RELAXED_CONTINUATION */
  1412.         if (nextc() == '\n') {
  1413.             sourceline++;
  1414.             goto retry;
  1415.         } else
  1416.             yyerror("backslash not last character on line");
  1417.         break;
  1418.  
  1419.     case '$':
  1420.         want_assign = TRUE;
  1421.         return lasttok = '$';
  1422.  
  1423.     case ':':
  1424.     case '?':
  1425.         allow_newline();
  1426.         /* fall through */
  1427.     case ')':
  1428.     case ']':
  1429.     case '(':    
  1430.     case '[':
  1431.     case ';':
  1432.     case '{':
  1433.     case ',':
  1434.         return lasttok = c;
  1435.  
  1436.     case '*':
  1437.         if ((c = nextc()) == '=') {
  1438.             yylval.nodetypeval = Node_assign_times;
  1439.             return lasttok = ASSIGNOP;
  1440.         } else if (do_posix) {
  1441.             pushback();
  1442.             return lasttok = '*';
  1443.         } else if (c == '*') {
  1444.             /* make ** and **= aliases for ^ and ^= */
  1445.             static int did_warn_op = FALSE, did_warn_assgn = FALSE;
  1446.  
  1447.             if (nextc() == '=') {
  1448.                 if (do_lint && ! did_warn_assgn) {
  1449.                     did_warn_assgn = TRUE;
  1450.                     warning("**= is not allowed by POSIX");
  1451.                     warning("operator `**=' is not supported in old awk");
  1452.                 }
  1453.                 yylval.nodetypeval = Node_assign_exp;
  1454.                 return ASSIGNOP;
  1455.             } else {
  1456.                 pushback();
  1457.                 if (do_lint && ! did_warn_op) {
  1458.                     did_warn_op = TRUE;
  1459.                     warning("** is not allowed by POSIX");
  1460.                     warning("operator `**' is not supported in old awk");
  1461.                 }
  1462.                 return lasttok = '^';
  1463.             }
  1464.         }
  1465.         pushback();
  1466.         return lasttok = '*';
  1467.  
  1468.     case '/':
  1469.         if (want_assign) {
  1470.             if (nextc() == '=') {
  1471.                 yylval.nodetypeval = Node_assign_quotient;
  1472.                 return lasttok = ASSIGNOP;
  1473.             }
  1474.             pushback();
  1475.         }
  1476.         return lasttok = '/';
  1477.  
  1478.     case '%':
  1479.         if (nextc() == '=') {
  1480.             yylval.nodetypeval = Node_assign_mod;
  1481.             return lasttok = ASSIGNOP;
  1482.         }
  1483.         pushback();
  1484.         return lasttok = '%';
  1485.  
  1486.     case '^':
  1487.     {
  1488.         static int did_warn_op = FALSE, did_warn_assgn = FALSE;
  1489.  
  1490.         if (nextc() == '=') {
  1491.             if (do_lint && ! did_warn_assgn) {
  1492.                 did_warn_assgn = TRUE;
  1493.                 warning("operator `^=' is not supported in old awk");
  1494.             }
  1495.             yylval.nodetypeval = Node_assign_exp;
  1496.             return lasttok = ASSIGNOP;
  1497.         }
  1498.         pushback();
  1499.         if (do_lint && ! did_warn_op) {
  1500.             did_warn_op = TRUE;
  1501.             warning("operator `^' is not supported in old awk");
  1502.         }
  1503.         return lasttok = '^';
  1504.     }
  1505.  
  1506.     case '+':
  1507.         if ((c = nextc()) == '=') {
  1508.             yylval.nodetypeval = Node_assign_plus;
  1509.             return lasttok = ASSIGNOP;
  1510.         }
  1511.         if (c == '+')
  1512.             return lasttok = INCREMENT;
  1513.         pushback();
  1514.         return lasttok = '+';
  1515.  
  1516.     case '!':
  1517.         if ((c = nextc()) == '=') {
  1518.             yylval.nodetypeval = Node_notequal;
  1519.             return lasttok = RELOP;
  1520.         }
  1521.         if (c == '~') {
  1522.             yylval.nodetypeval = Node_nomatch;
  1523.             want_assign = FALSE;
  1524.             return lasttok = MATCHOP;
  1525.         }
  1526.         pushback();
  1527.         return lasttok = '!';
  1528.  
  1529.     case '<':
  1530.         if (nextc() == '=') {
  1531.             yylval.nodetypeval = Node_leq;
  1532.             return lasttok = RELOP;
  1533.         }
  1534.         yylval.nodetypeval = Node_less;
  1535.         pushback();
  1536.         return lasttok = '<';
  1537.  
  1538.     case '=':
  1539.         if (nextc() == '=') {
  1540.             yylval.nodetypeval = Node_equal;
  1541.             return lasttok = RELOP;
  1542.         }
  1543.         yylval.nodetypeval = Node_assign;
  1544.         pushback();
  1545.         return lasttok = ASSIGNOP;
  1546.  
  1547.     case '>':
  1548.         if ((c = nextc()) == '=') {
  1549.             yylval.nodetypeval = Node_geq;
  1550.             return lasttok = RELOP;
  1551.         } else if (c == '>') {
  1552.             yylval.nodetypeval = Node_redirect_append;
  1553.             return lasttok = APPEND_OP;
  1554.         }
  1555.         yylval.nodetypeval = Node_greater;
  1556.         pushback();
  1557.         return lasttok = '>';
  1558.  
  1559.     case '~':
  1560.         yylval.nodetypeval = Node_match;
  1561.         want_assign = FALSE;
  1562.         return lasttok = MATCHOP;
  1563.  
  1564.     case '}':
  1565.         /*
  1566.          * Added did newline stuff.  Easier than
  1567.          * hacking the grammar.
  1568.          */
  1569.         if (did_newline) {
  1570.             did_newline = FALSE;
  1571.             return lasttok = c;
  1572.         }
  1573.         did_newline++;
  1574.         --lexptr;    /* pick up } next time */
  1575.         return lasttok = NEWLINE;
  1576.  
  1577.     case '"':
  1578.         esc_seen = FALSE;
  1579.         while ((c = nextc()) != '"') {
  1580.             if (c == '\n') {
  1581.                 pushback();
  1582.                 yyerror("unterminated string");
  1583.             }
  1584.             if (c == '\\') {
  1585.                 c = nextc();
  1586.                 if (c == '\n') {
  1587.                     sourceline++;
  1588.                     continue;
  1589.                 }
  1590.                 esc_seen = TRUE;
  1591.                 tokadd('\\');
  1592.             }
  1593.             if (c == EOF) {
  1594.                 pushback();
  1595.                 yyerror("unterminated string");
  1596.             }
  1597.             tokadd(c);
  1598.         }
  1599.         yylval.nodeval = make_str_node(tokstart,
  1600.                     tok - tokstart, esc_seen ? SCAN : 0);
  1601.         yylval.nodeval->flags |= PERM;
  1602.         return lasttok = YSTRING;
  1603.  
  1604.     case '-':
  1605.         if ((c = nextc()) == '=') {
  1606.             yylval.nodetypeval = Node_assign_minus;
  1607.             return lasttok = ASSIGNOP;
  1608.         }
  1609.         if (c == '-')
  1610.             return lasttok = DECREMENT;
  1611.         pushback();
  1612.         return lasttok = '-';
  1613.  
  1614.     case '.':
  1615.         c = nextc();
  1616.         pushback();
  1617.         if (! isdigit(c))
  1618.             return lasttok = '.';
  1619.         else
  1620.             c = '.';
  1621.         /* FALL THROUGH */
  1622.     case '0':
  1623.     case '1':
  1624.     case '2':
  1625.     case '3':
  1626.     case '4':
  1627.     case '5':
  1628.     case '6':
  1629.     case '7':
  1630.     case '8':
  1631.     case '9':
  1632.         /* It's a number */
  1633.         for (;;) {
  1634.             int gotnumber = FALSE;
  1635.  
  1636.             tokadd(c);
  1637.             switch (c) {
  1638.             case '.':
  1639.                 if (seen_point) {
  1640.                     gotnumber = TRUE;
  1641.                     break;
  1642.                 }
  1643.                 seen_point = TRUE;
  1644.                 break;
  1645.             case 'e':
  1646.             case 'E':
  1647.                 if (seen_e) {
  1648.                     gotnumber = TRUE;
  1649.                     break;
  1650.                 }
  1651.                 seen_e = TRUE;
  1652.                 if ((c = nextc()) == '-' || c == '+')
  1653.                     tokadd(c);
  1654.                 else
  1655.                     pushback();
  1656.                 break;
  1657.             case '0':
  1658.             case '1':
  1659.             case '2':
  1660.             case '3':
  1661.             case '4':
  1662.             case '5':
  1663.             case '6':
  1664.             case '7':
  1665.             case '8':
  1666.             case '9':
  1667.                 break;
  1668.             default:
  1669.                 gotnumber = TRUE;
  1670.             }
  1671.             if (gotnumber)
  1672.                 break;
  1673.             c = nextc();
  1674.         }
  1675.         if (c != EOF)
  1676.             pushback();
  1677.         else if (do_lint && ! eof_warned) {
  1678.             warning("source file does not end in newline");
  1679.             eof_warned = TRUE;
  1680.         }
  1681.         tokadd('\0');
  1682.         yylval.nodeval = make_number(atof(tokstart));
  1683.         yylval.nodeval->flags |= PERM;
  1684.         return lasttok = YNUMBER;
  1685.  
  1686.     case '&':
  1687.         if ((c = nextc()) == '&') {
  1688.             yylval.nodetypeval = Node_and;
  1689.             allow_newline();
  1690.             want_assign = FALSE;
  1691.             return lasttok = LEX_AND;
  1692.         }
  1693.         pushback();
  1694.         return lasttok = '&';
  1695.  
  1696.     case '|':
  1697.         if ((c = nextc()) == '|') {
  1698.             yylval.nodetypeval = Node_or;
  1699.             allow_newline();
  1700.             want_assign = FALSE;
  1701.             return lasttok = LEX_OR;
  1702.         }
  1703.         pushback();
  1704.         return lasttok = '|';
  1705.     }
  1706.  
  1707.     if (c != '_' && ! isalpha(c))
  1708.         yyerror("Invalid char '%c' in expression\n", c);
  1709.  
  1710.     /* it's some type of name-type-thing.  Find its length. */
  1711.     tok = tokstart;
  1712.     while (is_identchar(c)) {
  1713.         tokadd(c);
  1714.         c = nextc();
  1715.     }
  1716.     tokadd('\0');
  1717.     emalloc(tokkey, char *, tok - tokstart, "yylex");
  1718.     memcpy(tokkey, tokstart, tok - tokstart);
  1719.     if (c != EOF)
  1720.         pushback();
  1721.     else if (do_lint && ! eof_warned) {
  1722.         warning("source file does not end in newline");
  1723.         eof_warned = TRUE;
  1724.     }
  1725.  
  1726.     /* See if it is a special token. */
  1727.     low = 0;
  1728.     high = (sizeof(tokentab) / sizeof(tokentab[0])) - 1;
  1729.     while (low <= high) {
  1730.         int i;
  1731.  
  1732.         mid = (low + high) / 2;
  1733.         c = *tokstart - tokentab[mid].operator[0];
  1734.         i = c ? c : strcmp(tokstart, tokentab[mid].operator);
  1735.  
  1736.         if (i < 0)        /* token < mid */
  1737.             high = mid - 1;
  1738.         else if (i > 0)        /* token > mid */
  1739.             low = mid + 1;
  1740.         else {
  1741.             if (do_lint) {
  1742.                 if (tokentab[mid].flags & GAWKX)
  1743.                     warning("%s() is a gawk extension",
  1744.                         tokentab[mid].operator);
  1745.                 if (tokentab[mid].flags & RESX)
  1746.                     warning("%s() is a Bell Labs extension",
  1747.                         tokentab[mid].operator);
  1748.                 if (tokentab[mid].flags & NOT_POSIX)
  1749.                     warning("POSIX does not allow %s",
  1750.                         tokentab[mid].operator);
  1751.             }
  1752.             if (do_lint_old && (tokentab[mid].flags & NOT_OLD))
  1753.                 warning("%s is not supported in old awk",
  1754.                         tokentab[mid].operator);
  1755.             if ((do_traditional && (tokentab[mid].flags & GAWKX))
  1756.                 || (do_posix && (tokentab[mid].flags & NOT_POSIX)))
  1757.                 break;
  1758.             if (tokentab[mid].class == LEX_BUILTIN
  1759.                 || tokentab[mid].class == LEX_LENGTH
  1760.                )
  1761.                 yylval.lval = mid;
  1762.             else
  1763.                 yylval.nodetypeval = tokentab[mid].value;
  1764.  
  1765.             free(tokkey);
  1766.             return lasttok = tokentab[mid].class;
  1767.         }
  1768.     }
  1769.  
  1770.     yylval.sval = tokkey;
  1771.     if (*lexptr == '(')
  1772.         return lasttok = FUNC_CALL;
  1773.     else {
  1774.         want_assign = TRUE;
  1775.         return lasttok = NAME;
  1776.     }
  1777. }
  1778.  
  1779. /* node_common --- common code for allocating a new node */
  1780.  
  1781. static NODE *
  1782. node_common(op)
  1783. NODETYPE op;
  1784. {
  1785.     register NODE *r;
  1786.  
  1787.     getnode(r);
  1788.     r->type = op;
  1789.     r->flags = MALLOC;
  1790.     /* if lookahead is NL, lineno is 1 too high */
  1791.     if (lexeme && *lexeme == '\n')
  1792.         r->source_line = sourceline - 1;
  1793.     else
  1794.         r->source_line = sourceline;
  1795.     r->source_file = source;
  1796.     return r;
  1797. }
  1798.  
  1799. /* node --- allocates a node with defined lnode and rnode. */
  1800.  
  1801. NODE *
  1802. node(left, op, right)
  1803. NODE *left, *right;
  1804. NODETYPE op;
  1805. {
  1806.     register NODE *r;
  1807.  
  1808.     r = node_common(op);
  1809.     r->lnode = left;
  1810.     r->rnode = right;
  1811.     return r;
  1812. }
  1813.  
  1814. /* snode ---    allocate a node with defined subnode and proc for builtin
  1815.         functions. Checks for arg. count and supplies defaults where
  1816.         possible. */
  1817.  
  1818. static NODE *
  1819. snode(subn, op, idx)
  1820. NODETYPE op;
  1821. int idx;
  1822. NODE *subn;
  1823. {
  1824.     register NODE *r;
  1825.     register NODE *n;
  1826.     int nexp = 0;
  1827.     int args_allowed;
  1828.  
  1829.     r = node_common(op);
  1830.  
  1831.     /* traverse expression list to see how many args. given */
  1832.     for (n = subn; n != NULL; n = n->rnode) {
  1833.         nexp++;
  1834.         if (nexp > 3)
  1835.             break;
  1836.     }
  1837.  
  1838.     /* check against how many args. are allowed for this builtin */
  1839.     args_allowed = tokentab[idx].flags & ARGS;
  1840.     if (args_allowed && (args_allowed & A(nexp)) == 0)
  1841.         fatal("%s() cannot have %d argument%c",
  1842.             tokentab[idx].operator, nexp, nexp == 1 ? ' ' : 's');
  1843.  
  1844.     r->proc = tokentab[idx].ptr;
  1845.  
  1846.     /* special case processing for a few builtins */
  1847.     if (nexp == 0 && r->proc == do_length) {
  1848.         subn = node(node(make_number(0.0), Node_field_spec, (NODE *) NULL),
  1849.                     Node_expression_list,
  1850.                 (NODE *) NULL);
  1851.     } else if (r->proc == do_match) {
  1852.         if (subn->rnode->lnode->type != Node_regex)
  1853.             subn->rnode->lnode = mk_rexp(subn->rnode->lnode);
  1854.     } else if (r->proc == do_sub || r->proc == do_gsub) {
  1855.         if (subn->lnode->type != Node_regex)
  1856.             subn->lnode = mk_rexp(subn->lnode);
  1857.         if (nexp == 2)
  1858.             append_right(subn, node(node(make_number(0.0),
  1859.                              Node_field_spec,
  1860.                              (NODE *) NULL),
  1861.                             Node_expression_list,
  1862.                         (NODE *) NULL));
  1863.         else if (do_lint && subn->rnode->rnode->lnode->type == Node_val)
  1864.             warning("string literal as last arg of substitute");
  1865.     } else if (r->proc == do_gensub) {
  1866.         if (subn->lnode->type != Node_regex)
  1867.             subn->lnode = mk_rexp(subn->lnode);
  1868.         if (nexp == 3)
  1869.             append_right(subn, node(node(make_number(0.0),
  1870.                              Node_field_spec,
  1871.                              (NODE *) NULL),
  1872.                             Node_expression_list,
  1873.                         (NODE *) NULL));
  1874.     } else if (r->proc == do_split) {
  1875.         if (nexp == 2)
  1876.             append_right(subn,
  1877.                 node(FS_node, Node_expression_list, (NODE *) NULL));
  1878.         n = subn->rnode->rnode->lnode;
  1879.         if (n->type != Node_regex)
  1880.             subn->rnode->rnode->lnode = mk_rexp(n);
  1881.         if (nexp == 2)
  1882.             subn->rnode->rnode->lnode->re_flags |= FS_DFLT;
  1883.     }
  1884.  
  1885.     r->subnode = subn;
  1886.     return r;
  1887. }
  1888.  
  1889. /*
  1890.  * mkrangenode:
  1891.  * This allocates a Node_line_range node with defined condpair and
  1892.  * zeroes the trigger word to avoid the temptation of assuming that calling
  1893.  * 'node( foo, Node_line_range, 0)' will properly initialize 'triggered'. 
  1894.  * Otherwise like node().
  1895.  */
  1896.  
  1897. static NODE *
  1898. mkrangenode(cpair)
  1899. NODE *cpair;
  1900. {
  1901.     register NODE *r;
  1902.  
  1903.     getnode(r);
  1904.     r->type = Node_line_range;
  1905.     r->condpair = cpair;
  1906.     r->triggered = FALSE;
  1907.     return r;
  1908. }
  1909.  
  1910. /* make_for_loop --- build a for loop */
  1911.  
  1912. static NODE *
  1913. make_for_loop(init, cond, incr)
  1914. NODE *init, *cond, *incr;
  1915. {
  1916.     register FOR_LOOP_HEADER *r;
  1917.     NODE *n;
  1918.  
  1919.     emalloc(r, FOR_LOOP_HEADER *, sizeof(FOR_LOOP_HEADER), "make_for_loop");
  1920.     getnode(n);
  1921.     n->type = Node_illegal;
  1922.     r->init = init;
  1923.     r->cond = cond;
  1924.     r->incr = incr;
  1925.     n->sub.nodep.r.hd = r;
  1926.     return n;
  1927. }
  1928.  
  1929. /* dup_parms --- return TRUE if there are duplicate parameters */
  1930.  
  1931. static int
  1932. dup_parms(func)
  1933. NODE *func;
  1934. {
  1935.     register NODE *np;
  1936.     char *fname, **names;
  1937.     int count, i, j, dups;
  1938.     NODE *params;
  1939.  
  1940.     fname = func->param;
  1941.     count = func->param_cnt;
  1942.     params = func->rnode;
  1943.  
  1944.     if (count == 0)        /* no args, no problem */
  1945.         return FALSE;
  1946.  
  1947.     emalloc(names, char **, count * sizeof(char *), "dup_parms");
  1948.  
  1949.     i = 0;
  1950.     for (np = params; np != NULL; np = np->rnode)
  1951.         names[i++] = np->param;
  1952.  
  1953.     dups = 0;
  1954.     for (i = 1; i < count; i++) {
  1955.         for (j = 0; j < i; j++) {
  1956.             if (strcmp(names[i], names[j]) == 0) {
  1957.                 dups++;
  1958.                 error(
  1959.     "function `%s': parameter #%d, `%s', duplicates parameter #%d",
  1960.                     fname, i+1, names[j], j+1);
  1961.             }
  1962.         }
  1963.     }
  1964.  
  1965.     free(names);
  1966.     return (dups > 0 ? TRUE : FALSE);
  1967. }
  1968.  
  1969. /*
  1970.  * install:
  1971.  * Install a name in the symbol table, even if it is already there.
  1972.  * Caller must check against redefinition if that is desired. 
  1973.  */
  1974.  
  1975. NODE *
  1976. install(name, value)
  1977. char *name;
  1978. NODE *value;
  1979. {
  1980.     register NODE *hp;
  1981.     register size_t len;
  1982.     register int bucket;
  1983.  
  1984.     len = strlen(name);
  1985.     bucket = hash(name, len, (unsigned long) HASHSIZE);
  1986.     getnode(hp);
  1987.     hp->type = Node_hashnode;
  1988.     hp->hnext = variables[bucket];
  1989.     variables[bucket] = hp;
  1990.     hp->hlength = len;
  1991.     hp->hvalue = value;
  1992.     hp->hname = name;
  1993.     hp->hvalue->vname = name;
  1994.     return hp->hvalue;
  1995. }
  1996.  
  1997. /* lookup --- find the most recent hash node for name installed by install */
  1998.  
  1999. NODE *
  2000. lookup(name)
  2001. const char *name;
  2002. {
  2003.     register NODE *bucket;
  2004.     register size_t len;
  2005.  
  2006.     len = strlen(name);
  2007.     for (bucket = variables[hash(name, len, (unsigned long) HASHSIZE)];
  2008.             bucket != NULL; bucket = bucket->hnext)
  2009.         if (bucket->hlength == len && STREQN(bucket->hname, name, len))
  2010.             return bucket->hvalue;
  2011.  
  2012.     return NULL;
  2013. }
  2014.  
  2015. /*
  2016.  * append_right:
  2017.  * Add new to the rightmost branch of LIST.  This uses n^2 time, so we make
  2018.  * a simple attempt at optimizing it.
  2019.  */
  2020.  
  2021. static NODE *
  2022. append_right(list, new)
  2023. NODE *list, *new;
  2024. {
  2025.     register NODE *oldlist;
  2026.     static NODE *savefront = NULL, *savetail = NULL;
  2027.  
  2028.     oldlist = list;
  2029.     if (savefront == oldlist) {
  2030.         savetail = savetail->rnode = new;
  2031.         return oldlist;
  2032.     } else
  2033.         savefront = oldlist;
  2034.     while (list->rnode != NULL)
  2035.         list = list->rnode;
  2036.     savetail = list->rnode = new;
  2037.     return oldlist;
  2038. }
  2039.  
  2040. /*
  2041.  * func_install:
  2042.  * check if name is already installed;  if so, it had better have Null value,
  2043.  * in which case def is added as the value. Otherwise, install name with def
  2044.  * as value. 
  2045.  */
  2046.  
  2047. static void
  2048. func_install(params, def)
  2049. NODE *params;
  2050. NODE *def;
  2051. {
  2052.     NODE *r;
  2053.  
  2054.     pop_params(params->rnode);
  2055.     pop_var(params, FALSE);
  2056.     r = lookup(params->param);
  2057.     if (r != NULL) {
  2058.         fatal("function name `%s' previously defined", params->param);
  2059.     } else
  2060.         (void) install(params->param, node(params, Node_func, def));
  2061.  
  2062.     func_use(params->param, FUNC_DEFINE);
  2063. }
  2064.  
  2065. /* pop_var --- remove a variable from the symbol table */
  2066.  
  2067. static void
  2068. pop_var(np, freeit)
  2069. NODE *np;
  2070. int freeit;
  2071. {
  2072.     register NODE *bucket, **save;
  2073.     register size_t len;
  2074.     char *name;
  2075.  
  2076.     name = np->param;
  2077.     len = strlen(name);
  2078.     save = &(variables[hash(name, len, (unsigned long) HASHSIZE)]);
  2079.     for (bucket = *save; bucket != NULL; bucket = bucket->hnext) {
  2080.         if (len == bucket->hlength && STREQN(bucket->hname, name, len)) {
  2081.             *save = bucket->hnext;
  2082.             freenode(bucket);
  2083.             if (freeit)
  2084.                 free(np->param);
  2085.             return;
  2086.         }
  2087.         save = &(bucket->hnext);
  2088.     }
  2089. }
  2090.  
  2091. /* pop_params --- remove list of function parameters from symbol table */
  2092.  
  2093. /*
  2094.  * pop parameters out of the symbol table. do this in reverse order to
  2095.  * avoid reading freed memory if there were duplicated parameters.
  2096.  */
  2097. static void
  2098. pop_params(params)
  2099. NODE *params;
  2100. {
  2101.     if (params == NULL)
  2102.         return;
  2103.     pop_params(params->rnode);
  2104.     pop_var(params, TRUE);
  2105. }
  2106.  
  2107. /* make_param --- make NAME into a function parameter */
  2108.  
  2109. static NODE *
  2110. make_param(name)
  2111. char *name;
  2112. {
  2113.     NODE *r;
  2114.  
  2115.     getnode(r);
  2116.     r->type = Node_param_list;
  2117.     r->rnode = NULL;
  2118.     r->param = name;
  2119.     r->param_cnt = param_counter++;
  2120.     return (install(name, r));
  2121. }
  2122.  
  2123. static struct fdesc {
  2124.     char *name;
  2125.     short used;
  2126.     short defined;
  2127.     struct fdesc *next;
  2128. } *ftable[HASHSIZE];
  2129.  
  2130. /* func_use --- track uses and definitions of functions */
  2131.  
  2132. static void
  2133. func_use(name, how)
  2134. char *name;
  2135. enum defref how;
  2136. {
  2137.     struct fdesc *fp;
  2138.     int len;
  2139.     int ind;
  2140.  
  2141.     len = strlen(name);
  2142.     ind = hash(name, len, HASHSIZE);
  2143.  
  2144.     for (fp = ftable[ind]; fp != NULL; fp = fp->next) {
  2145.         if (strcmp(fp->name, name) == 0) {
  2146.             if (how == FUNC_DEFINE)
  2147.                 fp->defined++;
  2148.             else
  2149.                 fp->used++;
  2150.             return;
  2151.         }
  2152.     }
  2153.  
  2154.     /* not in the table, fall through to allocate a new one */
  2155.  
  2156.     emalloc(fp, struct fdesc *, sizeof(struct fdesc), "func_use");
  2157.     memset(fp, '\0', sizeof(struct fdesc));
  2158.     emalloc(fp->name, char *, len + 1, "func_use");
  2159.     strcpy(fp->name, name);
  2160.     if (how == FUNC_DEFINE)
  2161.         fp->defined++;
  2162.     else
  2163.         fp->used++;
  2164.     fp->next = ftable[ind];
  2165.     ftable[ind] = fp;
  2166. }
  2167.  
  2168. /* check_funcs --- verify functions that are called but not defined */
  2169.  
  2170. static void
  2171. check_funcs()
  2172. {
  2173.     struct fdesc *fp, *next;
  2174.     int i;
  2175.  
  2176.     for (i = 0; i < HASHSIZE; i++) {
  2177.         for (fp = ftable[i]; fp != NULL; fp = fp->next) {
  2178. #ifdef REALLYMEAN
  2179.             /* making this the default breaks old code. sigh. */
  2180.             if (fp->defined == 0) {
  2181.                 error(
  2182.         "function `%s' called but never defined", fp->name);
  2183.                 errcount++;
  2184.             }
  2185. #else
  2186.             if (do_lint && fp->defined == 0)
  2187.                 warning(
  2188.         "function `%s' called but never defined", fp->name);
  2189. #endif
  2190.             if (do_lint && fp->used == 0) {
  2191.                 warning("function `%s' defined but never called",
  2192.                     fp->name);
  2193.             }
  2194.         }
  2195.     }
  2196.  
  2197.     /* now let's free all the memory */
  2198.     for (i = 0; i < HASHSIZE; i++) {
  2199.         for (fp = ftable[i]; fp != NULL; fp = next) {
  2200.             next = fp->next;
  2201.             free(fp->name);
  2202.             free(fp);
  2203.         }
  2204.     }
  2205. }
  2206.  
  2207. /* param_sanity --- look for parameters that are regexp constants */
  2208.  
  2209. static void
  2210. param_sanity(arglist)
  2211. NODE *arglist;
  2212. {
  2213.     NODE *argp, *arg;
  2214.     int i;
  2215.  
  2216.     for (i = 1, argp = arglist; argp != NULL; argp = argp->rnode, i++) {
  2217.         arg = argp->lnode;
  2218.         if (arg->type == Node_regex)
  2219.             warning("regexp constant for parameter #%d yields boolean value", i);
  2220.     }
  2221. }
  2222.  
  2223. /* variable --- make sure NAME is in the symbol table */
  2224.  
  2225. NODE *
  2226. variable(name, can_free, type)
  2227. char *name;
  2228. int can_free;
  2229. NODETYPE type;
  2230. {
  2231.     register NODE *r;
  2232.     static int env_loaded = FALSE;
  2233.  
  2234.     if (! env_loaded && STREQ(name, "ENVIRON")) {
  2235.         load_environ();
  2236.         env_loaded = TRUE;
  2237.     }
  2238.     if ((r = lookup(name)) == NULL)
  2239.         r = install(name, node(Nnull_string, type, (NODE *) NULL));
  2240.     else if (can_free)
  2241.         free(name);
  2242.     return r;
  2243. }
  2244.  
  2245. /* mk_rexp --- make a regular expression constant */
  2246.  
  2247. static NODE *
  2248. mk_rexp(exp)
  2249. NODE *exp;
  2250. {
  2251.     NODE *n;
  2252.  
  2253.     if (exp->type == Node_regex)
  2254.         return exp;
  2255.  
  2256.     getnode(n);
  2257.     n->type = Node_regex;
  2258.     n->re_exp = exp;
  2259.     n->re_text = NULL;
  2260.     n->re_reg = NULL;
  2261.     n->re_flags = 0;
  2262.     n->re_cnt = 1;
  2263.     return n;
  2264. }
  2265.  
  2266. /* isnoeffect --- when used as a statement, has no side effects */
  2267.  
  2268. /*
  2269.  * To be completely general, we should recursively walk the parse
  2270.  * tree, to make sure that all the subexpressions also have no effect.
  2271.  * Instead, we just weaken the actual warning that's printed, up above
  2272.  * in the grammar.
  2273.  */
  2274.  
  2275. static int
  2276. isnoeffect(type)
  2277. NODETYPE type;
  2278. {
  2279.     switch (type) {
  2280.     case Node_times:
  2281.     case Node_quotient:
  2282.     case Node_mod:
  2283.     case Node_plus:
  2284.     case Node_minus:
  2285.     case Node_subscript:
  2286.     case Node_concat:
  2287.     case Node_exp:
  2288.     case Node_unary_minus:
  2289.     case Node_field_spec:
  2290.     case Node_and:
  2291.     case Node_or:
  2292.     case Node_equal:
  2293.     case Node_notequal:
  2294.     case Node_less:
  2295.     case Node_greater:
  2296.     case Node_leq:
  2297.     case Node_geq:
  2298.     case Node_match:
  2299.     case Node_nomatch:
  2300.     case Node_not:
  2301.     case Node_val:
  2302.     case Node_in_array:
  2303.     case Node_NF:
  2304.     case Node_NR:
  2305.     case Node_FNR:
  2306.     case Node_FS:
  2307.     case Node_RS:
  2308.     case Node_FIELDWIDTHS:
  2309.     case Node_IGNORECASE:
  2310.     case Node_OFS:
  2311.     case Node_ORS:
  2312.     case Node_OFMT:
  2313.     case Node_CONVFMT:
  2314.         return TRUE;
  2315.     default:
  2316.         break;    /* keeps gcc -Wall happy */
  2317.     }
  2318.  
  2319.     return FALSE;
  2320. }
  2321.